<template>
  <div class="main-content-box">
    <div class="demoDiv">
      <div class="title_for_layout">
        <h3>不确定X、Y坐标值，单个设备，力导向布局(定制不同节点的参数)</h3>
        <h3>此例为初级实现版本，功能未完全实现（边的动态点击显示）</h3>
      </div>
      <div class="toolDiv">
        <div class="zoom zoomOut" title="放大" @click="getZoomOut">
          <i class="iconfont">&#xe640;</i>
        </div>
        <div class="zoom zoomIn" title="缩小" @click="getZoomIn">
          <i class="iconfont">&#xe624;</i>
        </div>
        <div class="zoom subNodes" title="二级" @click="showSubNodes">
          <i class="iconfont">&#xe614;</i>
        </div>
        <div class="zoom allViews" title="全部线路" @click="showAllViews">
          <i class="iconfont">&#xe697;</i>
        </div>
        <div class="zoom refreshViews" title="刷新拓扑图" @click="refreshViews">
          <i class="iconfont">&#xe64d;</i>
        </div>
        <div class="zoom thirdNodes" title="还原" @click="reFreshNodeOrg">
          <i class="iconfont">&#xe649;</i>
        </div>
      </div>
      <div id="container"></div>
    </div>
  </div>
</template>

<script>
import G6 from '@antv/g6';
import Util from "@antv/g6/lib/util";
export default {
  name: 'g6demo12',
  data () {
    return {
      currentGraph: {},
      lineEdge: [],
      lineEdgeArrOne: [],
      lineEdgeArrTwo: [],
      clickNum: 0,
      showNodeDetailsObj: {},
      showEdgeDetailsObj: {},
      /**
       * 数据格式：数据使用iconfont时，需要包含style、labelCfg、backgroundConfig
       */
      drawData: {
        nodes: [
          {
            id: 'node0',
            size: 80,
            label: 'xxx 交换机 \n xxx-1.0.1 bate',
            text: '\ue6ec',
            isCenter: true,
            isClick: false,
            style: {
              fill: 'red'
            },
            labelCfg: {
              style: {
                fill: "red"
              },
              position: 'bottom',
              offset: [110, 10, 10, 10],
            },
            backgroundConfig: null,  // 自定义项，用于判读是否需要圆背景
          },
          {
            id: 'node1',
            size: 50,
            label: 'node1',
            isClick: false,
            text: '\ue68c',
            isFisrtNodes: true,
            style: {
              fill: 'skyblue'
            },
            labelCfg: {
              style: {
                fill: "skyblue"
              },
            },
            backgroundConfig: null,
          },
          {
            id: 'node2',
            size: 50,
            label: 'node2',
            isClick: false,
            text: '\ue68c',
            isFisrtNodes: true,
            style: {
              fill: 'skyblue'
            },
            labelCfg: {
              style: {
                fill: "skyblue"
              },
            },
            backgroundConfig: null,
          },
          {
            id: 'node3',
            size: 50,
            label: 'node3',
            isClick: false,
            text: '\ue68c',
            isFisrtNodes: true,
            style: {
              fill: 'skyblue'
            },
            labelCfg: {
              style: {
                fill: "skyblue"
              },
            },
            backgroundConfig: null
          },
          {
            id: 'node4',
            size: 50,
            label: 'node4',
            isClick: false,
            isLeaf: true,
            text: '\ue78a',
            isFisrtNodes: true,
            style: {
              fill: 'skyblue'
            },
            labelCfg: {
              style: {
                fill: "skyblue"
              },
            },
            backgroundConfig: null,
          },
          {
            id: 'node5',
            size: 50,
            label: 'node5',
            isClick: false,
            isLeaf: true,
            text: '\ue78a',
            isFisrtNodes: true,
            style: {
              fill: 'skyblue'
            },
            labelCfg: {
              style: {
                fill: "skyblue"
              },
            },
            backgroundConfig: null,
          },
          {
            id: 'node6',
            size: 30,
            label: 'node6',
            isClick: false,
            isLeaf: true,
            text: '\ue78a',
            isSubNodes: true,
            style: {
              fill: 'green'
            },
            labelCfg: {
              style: {
                fill: "skyblue"
              },
            },
            backgroundConfig: null,
          },
          {
            id: 'node7',
            size: 30,
            label: 'node7',
            isClick: false,
            isLeaf: true,
            text: '\ue78a',
            isSubNodes: true,
            style: {
              fill: 'green'
            },
            labelCfg: {
              style: {
                fill: "skyblue"
              },
            },
            backgroundConfig: null,
          },
          {
            id: 'node8',
            size: 30,
            label: 'node8',
            isClick: false,
            isLeaf: true,
            isSubNodes: true,
            text: '\ue78a',
            style: {
              fill: 'green'
            },
            labelCfg: {
              style: {
                fill: "skyblue"
              },
            },
            backgroundConfig: null,
          },
          {
            id: 'node9',
            size: 30,
            label: 'node9',
            isClick: false,
            isLeaf: true,
            isSubNodes: true,
            text: '\ue78a',
            style: {
              fill: 'green'
            },
            labelCfg: {
              style: {
                fill: "skyblue"
              },
            },
            backgroundConfig: null,
          },
          {
            id: 'node10',
            size: 30,
            label: 'node10',
            isClick: false,
            isLeaf: true,
            isSubNodes: true,
            text: '\ue78a',
            style: {
              fill: 'green'
            },
            labelCfg: {
              style: {
                fill: "skyblue"
              },
            },
            backgroundConfig: null,
          },
          {
            id: 'node11',
            size: 30,
            label: 'node11',
            isClick: false,
            isLeaf: true,
            isSubNodes: true,
            text: '\ue78a',
            style: {
              fill: 'green'
            },
            labelCfg: {
              style: {
                fill: "skyblue"
              },
            },
            backgroundConfig: null,
          },
          {
            id: 'node12',
            size: 30,
            label: 'node12',
            isClick: false,
            isLeaf: true,
            isSubNodes: true,
            text: '\ue78a',
            style: {
              fill: 'green'
            },
            labelCfg: {
              style: {
                fill: "skyblue"
              },
            },
            backgroundConfig: null,
          },
          {
            id: 'node13',
            size: 30,
            label: 'node13',
            isClick: false,
            isLeaf: true,
            isSubNodes: true,
            text: '\ue78a',
            style: {
              fill: 'green'
            },
            labelCfg: {
              style: {
                fill: "skyblue"
              },
            },
            backgroundConfig: null,
          },
          {
            id: 'node14',
            size: 30,
            label: 'node14',
            isClick: false,
            isLeaf: true,
            isSubNodes: true,
            text: '\ue78a',
            style: {
              fill: 'green'
            },
            labelCfg: {
              style: {
                fill: "skyblue"
              },
            },
            backgroundConfig: null,
          },
          {
            id: 'node15',
            size: 30,
            label: 'node15',
            isClick: false,
            isLeaf: true,
            isSubNodes: true,
            text: '\ue78a',
            style: {
              fill: 'green'
            },
            labelCfg: {
              style: {
                fill: "skyblue"
              },
            },
            backgroundConfig: null,
          },
          {
            id: 'node16',
            size: 30,
            label: 'node16',
            isClick: false,
            isLeaf: true,
            isSubNodes: true,
            text: '\ue78a',
            style: {
              fill: 'green'
            },
            labelCfg: {
              style: {
                fill: "skyblue"
              },
            },
            backgroundConfig: null,
          },
          {
            id: 'node17',
            size: 15,
            label: 'node17',
            isClick: false,
            isLeaf: true,
            isThirdNodes: true,
            text: '\ue679',
            style: {
              fill: 'red'
            },
            labelCfg: {
              style: {
                fill: "orange"
              },
            },
            backgroundConfig: null,
          },
          {
            id: 'node18',
            size: 15,
            label: 'node18',
            isClick: false,
            isLeaf: true,
            isThirdNodes: true,
            text: '\ue743',
            style: {
              fill: 'black'
            },
            labelCfg: {
              style: {
                fill: "purple"
              },
            },
            backgroundConfig: null,
          },
        ],
        edges: [
          {
            source: 'node0',
            target: 'node1',
            label: 'node-edge1',
            lineNum: 2,
          },
          {
            source: 'node0',
            target: 'node2',
            label: 'node-edge2',
            lineNum: 2,
          },
          {
            source: 'node0',
            target: 'node3',
            label: 'node-edge3',
            lineNum: 2,
          },
          {
            source: 'node0',
            target: 'node4',
            label: 'node-edge4',
            lineNum: 2,
          },
          {
            source: 'node0',
            target: 'node5',
            label: 'node-edge5',
            lineNum: 2,
          },
          {
            source: 'node1',
            target: 'node6',
            label: 'node-edge6',
            lineNum: 2,
          },
          {
            source: 'node1',
            target: 'node7',
            label: 'node-edge7',
            lineNum: 2,
          },
          {
            source: 'node2',
            target: 'node8',
            label: 'node-edge8',
            lineNum: 2,
          },
          {
            source: 'node2',
            target: 'node9',
            label: 'node-edge9',
            lineNum: 2,
          },
          {
            source: 'node2',
            target: 'node10',
            label: 'node-edge10',
            lineNum: 2,
          },
          {
            source: 'node2',
            target: 'node11',
            label: 'node-edge11',
            lineNum: 2,
          },
          {
            source: 'node2',
            target: 'node12',
            label: 'node-edge12',
            lineNum: 2,
          },
          {
            source: 'node2',
            target: 'node13',
            label: 'node-edge13',
            lineNum: 2,
          },
          {
            source: 'node3',
            target: 'node14',
            label: 'node-edge14',
            lineNum: 2,
          },
          {
            source: 'node3',
            target: 'node15',
            label: 'node-edge15',
            lineNum: 2,
          },
          {
            source: 'node3',
            target: 'node16',
            label: 'node-edge16',
            lineNum: 2,
          },
          {
            source: 'node16',
            target: 'node17',
            label: 'node-edge17',
            lineNum: 2,
          },
          {
            source: 'node16',
            target: 'node18',
            label: 'node-edge18',
            lineNum: 2,
          },
        ],
      },
      tempData: {
        nodes: [],
        edges: []
      },
      isClickNodes: false,
      middleTemp: {
        nodes: [],
        edges: []
      },
      isClickRefresh: false
    }
  },
  mounted () {
    this.getFirstNodes()
    this.initGrahp()
  },
  methods: {
    initGrahp () {
      let _that = this  //保存vue实例
      /**
       * 使用iconfont
       */
      G6.registerNode('iconfont', {
        draw (cfg, group) {
          const { backgroundConfig: backgroundStyle, style, labelCfg: labelStyle } = cfg;

          if (backgroundStyle) {
            group.addShape('circle', {
              attrs: {
                x: 0,
                y: 0,
                r: cfg.size,
                ...backgroundStyle,
              },
              name: 'circle-shape',
            });
          }

          const keyShape = group.addShape('text', {
            attrs: {
              x: 0,
              y: 0,
              fontFamily: 'iconfont', // 对应css里面的font-family: "iconfont";
              textAlign: 'center',
              textBaseline: 'middle',
              text: cfg.text,
              fontSize: cfg.size,
              // lineHeight: 44,
              ...style,
            },
            name: 'text-shape1',
          });
          const labelY = backgroundStyle ? cfg.size * 2 : cfg.size;

          group.addShape('text', {
            attrs: {
              x: 0,
              y: labelY,
              textAlign: 'center',
              textBaseline: 'middle',
              text: cfg.label,
              ...labelStyle.style,
            },
            name: 'text-shape1',
          });
          return keyShape;
        },
      });
      /**
       * 添加右键点击节点的菜单及事件
       */
      const conextMenuContainer = document.createElement('ul');
      conextMenuContainer.id = 'contextMenu';

      // create li
      const firstLi = document.createElement('li');
      firstLi.innerHTML = `查看节点`;
      firstLi.addEventListener('click', function (ev) {
        console.log(ev)
        console.log('点击了第一个li')
        console.log(this)
        graph.changeData(_that.tempData);
      })
      conextMenuContainer.appendChild(firstLi);
      document.getElementById('container').appendChild(conextMenuContainer);

      const width = document.getElementById('container').scrollWidth;
      const height = document.getElementById('container').scrollHeight || 800;
      const graph = new G6.Graph({
        container: 'container',
        width,
        height,
        // renderer: 'svg',
        linkCenter: true,
        modes: {
          default: [
            'drag-canvas',
            'zoom-canvas',
            // 'drag-node'
          ]
        },
        layout: {
          type: 'force',
          preventOverlap: true,
          /**
           * 边长。可以使用回调函数的形式对不同对边定义不同边长
           */
          linkDistance: d => {
            // console.log(d)
            if (d.source.id === 'node0') {
              return 150;
            }
            if (d.source.isFisrtNodes) {
              return 100
            }
            if (d.source.isSubNodes) {
              return 60
            }
            if (d.source.isSubNodes && d.target.isThirdNodes) {
              return 40;
            }
            return 30
          },
          /**
           * 节点作用力，正数代表节点之间的引力作用，负数代表节点之间的斥力作用。
           * 可以使用回调函数的形式对不同对节点定义不同节点作用力
           */
          nodeStrength: d => {
            if (d.isLeaf) {
              return -100;
            }
            return -50;
          },
          /**
           * 边的作用力，默认根据节点的出入度自适应。可以使用回调函数的形式对不同对节点定义不同边作用力
           */
          edgeStrength: d => {
            if (d.source.id === 'node1' || d.source.id === 'node2' || d.source.id === 'node3') {
              return 0.7;
            }
            return 0.1;
          },
          /**
           * preventOverlap 为 true 时生效，防止重叠时节点边缘间距的最小值。
           * 可以是回调函数，为不同节点设置不同的最小间距，
           */
          nodeSpacing: d => {
            // d 是一个节点
            if (d.id === 'node1' || d.id === 'node2' || d.id === 'node3' || d.id === 'node4' || d.id === 'node5') {
              return 50;
            }
            return 10;
          },
          /**
           * 是否启用 web-worker 以防布局计算时间过长阻塞页面交互，默认false
           */
          workerEnabled: false
        },
        defaultNode: {
          backgroundConfig: {
            backgroundType: 'circle',
            fill: '#40a9ff',
            stroke: 'LightSkyBlue',
          },
          size: 36,
          color: '#5B8FF9',
          type: 'iconfont',
          style: {
            lineWidth: 2,
            fill: '#C6E5FF',
          },
          labelCfg: {
            // autoRotate: true, //标签文字是否跟随边旋转，默认 false
            offset: [60, 10, 10, 10],
            style: {
              fontSize: 14,
            },
          }
        },
        defaultEdge: {
          size: 1,
          color: '#e2e2e2',
          style: {
            lineWidth: 1,
            stroke: '#b5b5b5',
            lineAppendWidth: 10,
          },
          autoRotate: true,
          labelCfg: {
            autoRotate: true,
            style: {
              background: {
                fill: '#ffffff',
                stroke: '#9EC9FF',
                padding: [2, 2, 2, 2],
                radius: 2,
              },
            },
          },
        },
      });

      // const nodes = _that.drawData.nodes;
      /* graph.data({
        nodes: _that.tempData.nodes.map(function (node, i) {
          node.label = node.label ? node.label : node.id
          return Object.assign({}, node)
          // return node
        }),
        edges: _that.tempData.edges.map(function (edge, i) {
          edge.id = 'edge' + (i + 1);
          edge.label = edge.label ? edge.label : 'edge' + (i + 1)
          return Object.assign({}, edge);
          // return edge
        }),
      }); */
      graph.data(_that.tempData)
      graph.render();
      /**
       * 当节点开始被拖拽的时候触发的事件，此事件作用在被拖曳节点上
       */
      graph.on('node:dragstart', function (e) {
        graph.layout();
        refreshDragedNodePosition(e);
      });
      /**
       * 当节点在拖动过程中时触发的事件，此事件作用于被拖拽节点上
       */
      graph.on('node:drag', function (e) {
        refreshDragedNodePosition(e);
      });
      /**
       * 当拖拽完成后触发的事件，此事件作用在被拖曳节点上
       */
      graph.on('node:dragend', function (e) {
        e.item.get('model').fx = null;
        e.item.get('model').fy = null;
      });

      function refreshDragedNodePosition (e) {
        // console.log(e)
        const model = e.item.get('model');
        // console.log(model)
        model.fx = e.x;
        model.fy = e.y;
      }
      /**
       * 将实例化的G6，赋给data中的currentGraph
       */
      _that.currentGraph = graph
      /**
       * 右键点击事件
       */
      // let temporaryData = Object.assign({}, this.drawData)  //保存一份所有的原始数据信息
      let temporaryData = JSON.parse(JSON.stringify(this.drawData))  //保存一份所有的原始数据信息

      graph.on('node:contextmenu', evt => {
        evt.preventDefault();
        evt.stopPropagation();
        console.log(evt)
        conextMenuContainer.style.left = `${evt.canvasX + 36}px`; //使菜单出现在节点的右侧
        conextMenuContainer.style.top = `${evt.canvasY}px`;
        /**
         * 拿到与此节点相关的边的信息,再根据边查找到节点信息，然后添加边、节点
         */
        console.log(temporaryData)
        let showRelationId = evt.item._cfg.id
        console.log(showRelationId)
        let edgeTemp = []
        temporaryData.edges.forEach(item => {
          if (item.source === showRelationId) {
            edgeTemp.push(item)
          }
        })
        console.log(edgeTemp)
        let nodeTemp = []
        temporaryData.nodes.forEach(item => {
          edgeTemp.forEach(i => {
            if (i.target === item.id) {
              nodeTemp.push(item)
            }
          })
        })
        console.log(nodeTemp)
        /**
         * 存在问题，新增节点位置不可点击拖拽。
         */
        /* nodeTemp.forEach(itemNode => {
          graph.addItem('node', itemNode)
        })
        edgeTemp.forEach(itemEdge => {
          graph.addItem('edge', itemEdge)
        }) */

        /**
         * 右键事件 尝试方法2
         */
        let isClickTag = evt.item._cfg.model.isClick
        /**
         * 点击中心节点时，防止多次点击出现显示错误，进行的优化处理
         */
        if (evt.item._cfg.model.isCenter) {
          return
        }
        /**
         * 防止多次点击造成重复数据过多，显示出现问题
         * 将当前节点的后拿到的节点及边数据拼接到源数据中
         */
        if (!isClickTag) {
          _that.tempData.nodes = _that.tempData.nodes.concat(nodeTemp)
          _that.tempData.edges = _that.tempData.edges.concat(edgeTemp)
          evt.item._cfg.model.isClick = true
        }

        console.log(_that.tempData)
        // graph.changeData(_that.tempData);
        // graph.refresh()
        // console.log(graph.save())
      });

      graph.on('node:mouseleave', () => {
        conextMenuContainer.style.left = '-300px';
      });

      /**
       * 边的点击事件
       */
      graph.on('edge:click', ev => {
        console.log(ev)
        console.log('点击了一条边')
      })
      /**
       * 此方法为临时取消画布上节点出现阴影的解决方案
       */
      graph.get('canvas').set('localRefresh', false)
    },
    getZoomOut () {
      let currentZoom = this.currentGraph.getZoom();
      this.currentGraph.zoomTo(currentZoom + 0.1, this.getViewCenter());
    },
    getZoomIn () {
      const currentZoom = this.currentGraph.getZoom();
      this.currentGraph.zoomTo(currentZoom - 0.1, this.getViewCenter());
    },
    showSubNodes () {
      console.log('显示二级节点')
      this.currentGraph.destroy();
      /* this.drawData.nodes.forEach(item => {
        if (item.isSubNodes) {
          this.tempData.nodes.push(item)
        }
      }) */
      /* let xxx = this.drawData.nodes.filter((item, index, arr) => {
        return item.isSubNodes === true
      })
      console.log(xxx) */
      this.drawData.nodes.filter((item, index, arr) => {
        if (item.isSubNodes) {
          this.tempData.nodes.push(item)
        }
      })

      /**
       * 利用对象访问属性的方法，判断对象中是否存在某个key。
       * 从而达到去重的目的
       */
      let result = []
      let tempObj = {}
      for (let i = 0; i < this.tempData.nodes.length; i++) {
        if (!tempObj[this.tempData.nodes[i].id]) {
          result.push(this.tempData.nodes[i])
          tempObj[this.tempData.nodes[i].id] = true
        }
      }
      // console.log(tempObj)
      // console.log(result)
      /**
       * 此处为for循环中数组splice方法调用次数有误的解决方法
       * 由于splice() 方法通过删除或替换现有元素或者原地添加新的元素来修改数组,并以数组形式返回被修改的内容。
       * 此方法会改变原数组，意味着原数组的下标会发生变化
       */
      let deleteNum = 1
      let loop = result.length
      for (let j = 0; j < loop; j++) {
        if (result[j].isThirdNodes) {
          result.splice(j, deleteNum)
          j-- //改变下标
          loop = loop - deleteNum // 改变循环长度
        }
      }
      /* for (let j = loop - 1; j >= 0; j--) {
        if (result[j].isThirdNodes) {
          result.splice(j, 1)
        }
      } */
      this.tempData.nodes = result
      this.tempData.edges = this.drawData.edges.slice(0, this.tempData.nodes.length - 1)
      console.log(this.tempData)
      this.initGrahp()
      // this.currentGraph.changeData(this.tempData.nodes,this.tempData.edges)
    },
    reFreshNodeOrg () {
      console.log('还原节点')
      /**
       * 还原初始化显示节点信息，需要将此对象置为空
       */
      this.tempData = {
        nodes: [],
        edges: []
      }
      /**
       * 点击还原节点是，需要将源数据中所以的节点点击标识置为false
       * 否则会出现，点击显示节点后，还原节点后，原节点不显示展开的节点
       */
      this.drawData.nodes.forEach(item => {
        item.isClick = false
      })
      setTimeout(() => {
        this.currentGraph.destroy();
        this.getFirstNodes()
        this.initGrahp()
      }, 10)
    },
    showAllViews () {
      this.currentGraph.clear();
      this.currentGraph.destroy();
      this.tempData.nodes = this.drawData.nodes
      let result = []
      let tempObj = {}
      for (let k = 0; k < this.tempData.nodes.length; k++) {
        if (!tempObj[this.tempData.nodes[k].id]) {
          result.push(this.tempData.nodes[k])
          tempObj[this.tempData.nodes[k].id] = true
        }
      }
      this.tempData.nodes = result
      this.tempData.edges = this.drawData.edges
      this.initGrahp()
    },
    getFirstNodes () {
      /**
       * 先将中心节点push进tempData中
       */
      this.drawData.nodes.forEach(item => {
        if (item.isCenter) {
          this.tempData.nodes.push(item)
        }
        if (item.isFisrtNodes) {
          this.tempData.nodes.push(item)
        }
      })
      // console.log(this.tempData.nodes.length)
      /**
       * 此处边的数量较节点数 少 1
       */
      this.tempData.edges = this.drawData.edges.slice(0, this.tempData.nodes.length - 1)
      console.log(this.tempData)
      this.middleTemp.nodes = this.tempData.nodes
      this.middleTemp.edges = this.tempData.edges
    },
    refreshViews () {
      /**
       * 将graph实例销毁时，需要销毁画布
       */
      // this.currentGraph.clear();
      this.currentGraph.destroy();
      console.log('刷新视图')
      setTimeout(() => {
        this.initGrahp()
      }, 10)
      // this.currentGraph.changeData()
    },

    /**
     * 计算画布的padding值
     */
    getFormatPadding () {
      return Util.formatPadding(this.currentGraph.get("fitViewPadding"));
    },
    /**
     * 画布中心位置
     */
    getViewCenter () {
      const padding = this.getFormatPadding();
      const graph = this.currentGraph;
      const width = this.currentGraph.get("width");
      const height = graph.get("height");
      return {
        x: (width - padding[2] - padding[3]) / 2 + padding[3],
        y: (height - padding[0] - padding[2]) / 2 + padding[0]
      };
    },
    noRepeatArr (arr) {
      let result = []
      let tempObj = {}
      for (let i = 0; i < arr.length; i++) {
        if (!tempObj[arr[i].id]) {
          result.push(arr[i])
          tempObj[arr[i].id] = true
        }
      }
      return result
    },

  }
}
</script>

<style scoped>
.main-content-box {
  width: 95%;
  margin: 5px 20px;
}
.demoDiv {
  position: relative;
  padding: 20px;
  border: 1px solid skyblue;
}
.toolDiv {
  width: 50px;
  border: 1px solid #f5f5f5;
  position: absolute;
}

.zoom {
  cursor: pointer;
  border: 1px solid #f5f5f5;
  font-size: 26px;
  background-color: #ffffff;
}
/* 右键菜单及显示详情区域 */
.showDetails {
  width: 12vw;
  height: 40vh;
  border: 1px solid #f5f5f5;
  box-shadow: -5px 5px 5px #aaaaaa;
  position: absolute;
  top: 0;
  right: 0;
  border-radius: 4px;
  background-color: #ffffff;
  padding: 5px;
  overflow-y: auto;
  font-size: 12px;
}
.details-title {
  text-align: left;
}
.closeDetail {
  position: absolute;
  right: 8px;
  top: 18px;
  cursor: pointer;
}
.closeDetail:hover {
  color: #e27e7e;
}
.details-info {
  margin: 0 10px;
  background-color: aquamarine;
}
.details-info-items {
  background-color: #ffffff;
  display: flex;
}
.details-info-items:last-child {
  background-color: #ffffff;
  display: flex;
  flex-direction: column;
  align-items: baseline;
}
.info-items {
  font-size: 12px;
  color: #545454;
  text-align: left;
}
.info-items-label {
  color: #000000;
  text-align: left;
  width: 65px;
}
.info-items-description {
  height: 100px;
  width: 100%;
  border: 1px solid #d2bebe;
  margin-top: 0px;
  line-height: 24px;
}
/* 右键菜单 */
.demoDiv >>> #contextMenu {
  position: absolute;
  list-style-type: none;
  padding: 10px 8px;
  left: -300px;
  background-color: rgba(255, 255, 255, 0.9);
  border: 1px solid #e2e2e2;
  border-radius: 4px;
  font-size: 14px;
  color: #545454;
}
.demoDiv >>> #contextMenu li {
  cursor: pointer;
  list-style-type: none;
  list-style: none;
  margin-left: 0px;
}
.demoDiv >>> #contextMenu li:hover {
  color: #aaa;
}
.title_for_layout {
  position: absolute;
  top: 0;
  left: 100px;
  color: crimson;
}
</style>